package org.microsites.service.impl;

import org.microsites.domain.dao.LockDAO;
import org.microsites.domain.dao.UserDAO;
import org.microsites.domain.model.Lock;
import org.microsites.domain.model.User;
import org.microsites.security.LockingException;
import org.microsites.security.Secured;
import org.microsites.service.LockService;
import org.microsites.util.UserContext;

public class LockServiceImpl implements LockService {

	private LockDAO lockDAO;
	private UserContext userCtx;
	private UserDAO userDAO;
	private Long wipeInterval;

	private String generateKey(Class<?> entry, Long id) {
		return entry.getSimpleName() + ':' + id;
	}

	@Secured
	public void keep(Class<?> entry, Long id) throws LockingException {
		Lock l = lockDAO.load(generateKey(entry, id), userCtx.getUser().getId());

		if (l == null) throw new LockingException("Invalid lock");
		
		l.setTimestamp(System.currentTimeMillis());
		lockDAO.update(l);
	}

	@Secured
	public void lock(Class<?> entry, Long id) throws LockingException {
		String key = generateKey(entry, id);
		Lock l = lockDAO.load(key);

		if (l != null) {
		    if (!l.getUser().equals(userCtx.getUser().getId())) {
    			l.setPending(userCtx.getUser().getId());
    			lockDAO.update(l);
    			User u = userDAO.load(l.getUser());
    			throw new LockingException("Already locked by " + u.getName());
		    } else {
		        l.setTimestamp(System.currentTimeMillis());
		        lockDAO.update(l);
		    }
		} else {
    		l = new Lock();
    		l.setKey(key);
    		l.setTimestamp(System.currentTimeMillis());
    		l.setUser(userCtx.getUser().getId());
    		lockDAO.create(l);
		}
	}

	@Secured
	public void unlock(Class<?> entry, Long id) {
		Lock l = lockDAO.load(generateKey(entry, id), userCtx.getUser().getId());

		if (l == null) throw new LockingException("Invalid lock");

		lockDAO.delete(l.getKey());
	}

	@Override
	public void wipe() {
		lockDAO.wipe(System.currentTimeMillis() - wipeInterval);
	}

	public LockDAO getLockDAO() {
		return lockDAO;
	}

	public void setLockDAO(LockDAO lockDAO) {
		this.lockDAO = lockDAO;
	}

	public UserContext getUserCtx() {
		return userCtx;
	}

	public void setUserCtx(UserContext userCtx) {
		this.userCtx = userCtx;
	}

	public UserDAO getUserDAO() {
		return userDAO;
	}

	public void setUserDAO(UserDAO userDAO) {
		this.userDAO = userDAO;
	}

	public Long getWipeInterval() {
		return wipeInterval;
	}

	public void setWipeInterval(Long wipeInterval) {
		this.wipeInterval = wipeInterval;
	}

}
